(function (zn){

    var DOM, Component;

    zn.class('zn.ui.core.Element', {
        events: [
            'attach',
            'childAttach',
            'detach',
            'childDetach'
        ],
        properties: {
            name: null,
            owner: {
                get: function (){
                    return this._owner || this;
                },
                set: function (value){
                    this._owner = value;
                }
            },
            parent: null,
            children: null,
            $dom: {
                get: function (){
                    return this._dom;
                },
                readonly: true
            }
        },
        methods: {
            init: {
                auto: true,
                value: function () {
                    this._views = {};
                    this._children = new zn.data.List();
                },
                after: function (){
                    this.__parseViewMeta();
                }
            },
            view: function (name) {
                return name ? this._views[name] : this._views;
            },
            register: function (name, value, force) {
                var _views = this._views;
                if (_views && !(name in _views) || force) {
                    _views[name] = value;
                }
            },
            unregister: function (name) {
                var _views = this._views;
                if (_views && name in _views) {
                    delete _views[name];
                }
            },
            each: function (callback, context){
                return this._children.each(callback, context), this;
            },
            count: function (){
                return this._children.count;
            },
            dispose: function () {
                owner = null;
                parent = null;
                children.each(function (child){
                    child.dispose();
                });
                children = null;
                $dom.remove();
            },
            attach: function (parent, index) {
                if (!parent) {
                    return this._parent = null, false;
                }
                this.detach();

                var _owner = this._owner,
                    _dom = this.$dom,
                    _container = parent.$dom,
                    _children = parent.children;

                if (index >= 0 && index < _children.length) {
                    var _ref = _children[index],
                        _refContainer = _ref && _ref.$dom;

                    if (_refContainer) {
                        _container.insertBefore(_dom, _refContainer);
                        _children.insert(this, index);
                    }
                    else {
                        _container.appendChild(_dom);
                        _children.add(this);
                    }
                }
                else {
                    _container.appendChild(_dom);
                    _children.add(this);
                }

                parent.fire('childAttach', {
                    child: this,
                    owner: _owner
                });

                this.fire('attach', {
                    parent: parent,
                    owner: _owner
                });
                this._parent = parent;
                this._attached = true;
            },
            detach: function () {
                if (!this._attached) {
                    return false;
                }

                var _name = this._name,
                    _parent = this._parent,
                    _owner = this._owner,
                    _children = _parent.children;

                if(!_children.contains(this)){
                    return false;
                }
                _parent._dom.removeChild(this._dom);
                _children.remove(this);

                if (_name && _owner) {
                    _owner.unregister(_name);
                }

                _parent.fire('childDetach', {
                    child: this,
                    owner: _owner
                });
                this.fire('detach', {
                    parent: _parent,
                    owner: _owner
                });

                this._parent = null;
                this._owner = null;
                this._attached = false;
            },
            scan: function (model){
                throw new Error('The super class must be implement the scan method.');
            },
            __parseViewMeta: function (){
                ViewParser.parse(this);
            }
        }
    });

    var ViewParser = {
        parse: function (comp){
            var _cotr = comp.constructor,
                _view = _cotr.getMeta('view');

            if(!_view){
                return false;
            }

            if(!DOM){
                DOM = zn.ui.dom.DOM;
            }

            if(!Component){
                Component = zn.ui.core.Component;
            }

            return this.__parseView(_view, comp);
        },
        __parseView: function (view, comp){
            var _owner = comp.owner || comp;
            switch(zn.type(view)){
                case 'object':
                    this.__createElement(view, _owner).attach(comp);
                    break;
                case 'array':
                    zn.each(view, function (value){
                        this.__createElement(value, _owner).attach(comp);
                    }, this);
                    break;
            }
        },
        __createElement: function (view, owner) {
            var _name = view.$name,
                _tag = view.$tag || 'div',
                _type = view.$type,
                _events = view.$events || [],
                _props = view.$props || [],
                _content = view.$content,
                _element = null;

            if (_type) {
                var _clazz = zn.is(_type, 'string') ? zn.path(__global, _type) : _type;
                if (zn.is(_clazz, 'function')) {
                    _element = new _clazz();
                }
                else {
                    throw new Error('Component [' + _type + '] is not defined.');
                }

            } else {
                _element = new DOM(_tag);
            }

            _element.owner = owner;
            _element.name = _name;

            zn.each(_events, function (value, name) {
                _element.on(name, owner[value], owner);
            });

            zn.each(_props, function (value, name) {
                _element.bind(name, value);
            });

            switch(zn.type(_content)){
                case 'array':
                    zn.each(_content, function (_view) {
                        this.__createElement(_view, owner).attach(_element);
                    }, this);
                    break;
                case 'string':
                    _element.bind('content', _content);
                    break;
                case 'object':
                    this.__createElement(_content, owner).attach(_element);
                    break
            }

            if (_name) {
                owner.register(_name, _element);
            }

            return _element;
        }
    }

})(zn);
